本日是 FAQ Chatbot 專案的關鍵階段,目標是將 Day 24 建立的 FAISS 向量資料庫與 LLM 生成模型結合,實現完整的 RAG 工作流程。
任務目標 | 核心技術 |
---|---|
RAG 流程整合 | 理解並實作 Retriever + Generator 的串接。 |
知識檢索 | 透過 FAISS 檢索最相關的知識片段(Context)。 |
生成回答 | 將 Context 餵入 LLM,生成有依據的自然語言回答。 |
確保已安裝所有 RAG 核心套件:
pip install faiss-cpu sentence-transformers transformers torch
# === Step 1. 載入工具 ===
from sentence_transformers import SentenceTransformer
from transformers import pipeline
import faiss
import numpy as np
import pandas as pd # 確保載入 pandas,以便後續進階應用
# === Step 1. 載入工具 (保持不變) ===
# === Step 1. 載入工具 (保持不變) ===
from sentence_transformers import SentenceTransformer
from transformers import pipeline
import faiss
import numpy as np
import pandas as pd # 確保已載入 pandas
# ---Step 2: 載入並處理 CSV 知識庫 ---
try:
# 讀取 Day 23 產出的 CSV 檔案
data_df = pd.read_csv("google_faq.csv", encoding="utf-8-sig")
# 從 DataFrame 中提取問題和答案列表
knowledge_base_questions = data_df['question'].tolist()
knowledge_base_answers = data_df['answer'].tolist()
print(f" 已成功載入 {len(knowledge_base_questions)} 筆問答資料。")
print(f" 知識庫問題範例: {knowledge_base_questions[0]}")
except FileNotFoundError:
print(" 錯誤:找不到 'google_faq.csv' 檔案!請檢查檔案路徑。")
# 如果找不到檔案,可以選擇使用 Day 25 的假設資料繼續測試
knowledge_base_questions = ["預設問題 1", "預設問題 2"]
knowledge_base_answers = ["預設答案 1", "預設答案 2"]
# --- Step 3: 向量化並建立 FAISS 索引 ---
embedder = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
# 注意:我們只需將「問題」向量化,因為檢索是基於「問題的語義相似度」
embeddings = embedder.encode(
knowledge_base_questions,
convert_to_numpy=True
).astype('float32')
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(embeddings)
print(" 向量資料庫建立完成!索引大小:", index.ntotal)
===Step 4. 檢索函數 (Retriever) ===
def retrieve(query, top_k=2):
query_vec = embedder.encode([query], convert_to_numpy=True).astype('float32')
distances, indices = index.search(query_vec, top_k)
# 這裡,我們將檢索到的問題和答案配對起來作為 Context
retrieved_context = []
for i in indices[0]:
# 將檢索到的問題和對應的標準答案串接起來,作為 LLM 的 Context
doc = f"問題: {knowledge_base_questions[i]}. 答案: {knowledge_base_answers[i]}"
retrieved_context.append(doc)
return retrieved_context # 返回一個包含 Top-K 文本片段的列表
# === 測試:使用 CSV 資料集中的問題 ===
user_query = "如何建立 Google 帳號" # 語義相似,但非完全匹配的查詢
# 確保生成器已載入
# generator = pipeline("text-generation", model="distilgpt2")
print("\n 問題:", user_query)
print(" RAG 回答:\n", rag_answer(user_query))
可以詢問不同問題
在 RAG 整合測試中,雖然檢索器(Retriever)成功找到了相關知識,但生成器(Generator)輸出了不連貫或重複的內容。這是實務應用中常見的挑戰。
當輸入查詢 如何建立 Google 帳號
時,模型輸出了包含重複指令的混亂文本:
問題: 如何建立 Google 帳號
RAG 回答:
根據以下內容回答問題:問題: 如何建立 Google 帳號?. 答案: 前往 https://accounts.google.com/signup,填寫基本資料即可免費建立 Google 帳號。 問題: 如何設定 Google 雙重驗證?. 答案: 前往帳戶安全設定頁面,開啟「兩步驟驗證」並設定手機或安全金鑰。
問題:如何建立 Google 帳號
回答:如何建立 Google 答案: 答案: 前往帳戶安全設定手機或安全金鑰。 問題:如何建立 Google 答案:
這個問題主要出在 LLM 的生成階段,而非檢索階段。根本原因是:
distilgpt2
僅有 1.24 億參數,缺乏複雜的指令遵循和推理能力。問題:
)或輸出不連貫的 Token。要解決這個生成混亂(廣義上的幻覺)問題,必須提升生成器的指令遵循能力或簡化輸入:
策略 | 建議做法 | 效果 |
---|---|---|
升級生成模型 | 替換為 Llama 3 8B、Mistral 7B 或中文模型(如 Qwen/Llama 系列),必要時使用 API (GPT-3.5/Gemini)。 | 最有效的解決方案,顯著提升指令遵循能力和回答品質。 |
優化 Context 輸入 | 在檢索時,只將 answer 欄位的內容作為 Context 傳給 LLM,避免傳遞重複的 question 資訊。 |
簡化輸入,減少小模型混淆的可能性。 |
調整生成參數 | 設置 do_sample=False (貪婪搜索)並降低 temperature (例如 0.1-0.2)。 |
讓模型輸出更確定、更保守的結果,減少隨機和混亂的 Token 生成。 |
結論: 雖然 RAG 系統功能正確,但需要一個指令遵循能力更強大的 LLM 來處理複雜的 RAG Prompt,才能將檢索到的知識有效地轉化為高品質的答案。
組件 | 核心功能 | 實作方式/套件 | 備註 |
---|---|---|---|
Retriever | 檢索最相關的知識片段 (Context) | SentenceTransformer + FAISS |
關鍵在於語義相似度搜索 |
Generator | 根據 Context 產生自然語言回答 | Hugging Face pipeline (distilGPT2 ) |
Prompt Augmentation 是核心 |
Prompt Augmentation 是 RAG 的精華:將檢索到的 Context
與使用者 Query
結合,明確指令 LLM 進行有依據的回答,從而避免幻覺。